package top.lshaci.framework.web.exception.handler;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import top.lshaci.framework.common.exception.BaseException;
import top.lshaci.framework.common.model.JsonResponse;
import top.lshaci.framework.web.model.ExceptionMessage;
import top.lshaci.framework.web.utils.GlobalExceptionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

import static cn.hutool.http.HttpStatus.HTTP_BAD_REQUEST;

/**
 * <p>Global exception handler</p><br>
 *
 * <b>0.0.4: </b>Add method argumentExceptionHandler<br>
 * <b>1.0.4: </b>使用GlobalExceptionUtils来获取自定义的异常消息<br>
 * <b>1.0.8: </b>删除参数验证失败异常中的日志信息<br>
 *
 * @author lshaci
 * @since 0.0.3
 * @version 1.0.8
 */
@RestController
@ControllerAdvice
public class GlobalExceptionHandler {

	private static  final Log log = LogFactory.get();

	/**
	 * Base exception handler
	 *
	 * @param e the exception
	 * @return json response
	 */
    @ExceptionHandler(BaseException.class)
    public JsonResponse<Object> baseExceptionHandler(HttpServletRequest req, BaseException e) {
		log.error(e, "System anomaly => {} {}", req.getMethod(), req.getRequestURI());
        return JsonResponse.error(e.getCode(), e.getMessage());
    }

	/**
	 * BindException and MethodArgumentNotValidException handler
	 *
	 * @param e the exception
	 * @return json response
	 */
    @ExceptionHandler(value = { BindException.class, MethodArgumentNotValidException.class })
    public JsonResponse<Object> argumentExceptionHandler(HttpServletRequest req, Exception e) {
		log.error(e, "System anomaly => {} {}", req.getMethod(), req.getRequestURI());

		BindingResult bindingResult = null;

        if (e instanceof BindException) {
			bindingResult = ((BindException) e).getBindingResult();
        } else if (e instanceof MethodArgumentNotValidException) {
			bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
        }

        if (bindingResult == null) {
        	return JsonResponse.error();
		}

		List<FieldError> fieldErrors = bindingResult.getFieldErrors();

		final JsonResponse r = JsonResponse.error(HTTP_BAD_REQUEST, fieldErrors.get(0).getDefaultMessage());
		fieldErrors.stream().forEach(fe -> r.otherData(fe.getField(), fe.getDefaultMessage()));

        return r;
    }

	/**
	 * Default exception handler
	 *
	 * @param e the exception
	 * @return json response
	 */
    @ExceptionHandler(Exception.class)
    public JsonResponse<Object> defaultExceptionHandler(HttpServletRequest req, Exception e) {
		log.error(e, "System anomaly => {} {}", req.getMethod(), req.getRequestURI());

		ExceptionMessage message = GlobalExceptionUtils.get(e.getClass());

		return JsonResponse.error(message.getCode(), message.getMessage());
    }

}
